<template>
  <div
    class="fa-contract-page"
    :page="p"
    :style="style"
    :class="{ 'is-active': viewer.state.pageIndex === p }"
    @click="viewer.state.pageIndex = p"
  >
    <div class="fa-contract-page__wrap" :style="{ width: `${w}px` }">
      <img
        v-if="src"
        :src="src"
        class="fa-contract-page__img"
        :draggable="false"
        :lazy="imageState"
        @load="onLoaded"
        @error="onError"
      />

      <div v-else v-html="html" class="fa-contract-page__html" :draggable="false" :lazy="htmlState" />

      <WidgetArea v-if="viewer.widget" :doc="doc" :page="page" />
      <slot />
    </div>

    <RidingArea v-if="viewer.riding && viewer.state.pageCount !== 1" />
  </div>
</template>

<script lang="ts">
import {
  defineComponent,
  computed,
  PropType,
  ref,
  inject,
  getCurrentInstance,
  provide,
  Ref,
  watch,
  onMounted,
  toRef
} from 'vue'
import config from '@/config'
import { Viewer, PageData, DocData } from '@/types'
import WidgetArea from '../widget-area/WidgetArea.vue'
import RidingArea from '../riding-area/RidingArea.vue'

/** 加载状态 */
enum LoadStatus {
  /** 加载中 */
  LOADING = 'loading',
  /** 已加载 */
  LOADED = 'loaded',
  /** 加载失败 */
  ERROR = 'error'
}

/** 页面 HTML */
function usePageHtml(doc: Ref<DocData>, page: Ref<PageData>, state: Ref<LoadStatus>) {
  /** 合同控件 */
  const viewer = inject('Viewer') as Viewer

  /** 页面 HTML */
  const html = ref('')

  /** 监听页面数据 html */
  watch(
    () => page.value.html,
    val => (html.value = val || ''),
    { immediate: true }
  )

  onMounted(async () => {
    const { pageHtml } = viewer

    if (html.value || !pageHtml) return

    try {
      state.value = LoadStatus.LOADING

      html.value = page.value.html = (await pageHtml(doc.value, page.value)) || ''

      state.value = LoadStatus.LOADED
    } catch (e) {
      state.value = LoadStatus.ERROR
    }
  })

  return html
}

export default defineComponent({
  name: 'FaContractPage',

  components: { RidingArea, WidgetArea },

  props: {
    /** 页面数据 */
    page: {
      type: Object as PropType<PageData>,
      required: true,
      default: () =>
        ({
          w: config.page.width,
          h: config.page.height,
          p: 0,
          src: ''
        } as PageData)
    },

    /** 当前文档 */
    doc: {
      type: Object as PropType<DocData>,
      required: true
    },

    /** 当前页面累计高度 */
    cumulativeHeight: {
      type: Number,
      required: true
    },

    /** 显示宽度 */
    width: {
      type: Number,
      default: 0
    }
  },

  setup(props) {
    provide('ContractPage', getCurrentInstance()?.proxy)

    /** 合同控件 */
    const viewer = inject('Viewer') as Viewer

    /** 展示宽度 */
    const w = computed(() => props.width || props.page.w)

    /** 展示高度 */
    const h = computed(() => (w.value / props.page.w) * props.page.h)

    /** 图片加载状态 */
    const imageState = ref(LoadStatus.LOADING)

    /** 页面加载状态 */
    const htmlState = ref(LoadStatus.LOADED)

    return {
      /** 合同控件 */
      viewer: ref(viewer),

      /** 展示宽度 */
      w,

      /** 展示高度 */
      h,

      /** 页码 */
      p: computed(() => props.page.p),

      /** 页面图片地址 */
      src: computed(() => {
        const { page, doc } = props
        return page.src || viewer.pageSrc?.(doc, page) || ''
      }),

      /** 图片加载状态 */
      imageState,

      /** 加载成功 */
      onLoaded() {
        imageState.value = LoadStatus.LOADED
      },

      /** 加载失败 */
      onError() {
        imageState.value = LoadStatus.ERROR
      },

      /** 页面 HTML */
      html: usePageHtml(toRef(props, 'doc'), toRef(props, 'page'), htmlState),

      /** 页面加载状态 */
      htmlState,

      /** 页面样式 */
      style: computed(() => {
        const {
          cumulativeHeight,
          page: { h, p }
        } = props

        const {
          layout: { ridingActive, ridingWidth },
          zoom: { level: zoomLevel },
          pageSpacing
        } = viewer

        const width = w.value + (ridingActive ? ridingWidth : 0)

        const top = (cumulativeHeight || 0) - h + (pageSpacing / zoomLevel) * (p + 1)

        return {
          /** 页面宽度，包含骑缝区域 */
          width: `${width}px`,

          /** 页码高度 */
          height: `${h}px`,

          /** 顶部距离 */
          transform: `translate(-50%, ${top}px)`
        }
      })
    }
  }
})
</script>

<style lang="scss">
.fa-contract-page {
  position: absolute;
  top: 0;
  left: 50%;
  transition: width 0.3s linear;

  &:hover {
    z-index: 1;
  }

  /**
   * 页面激活比 hover 拥有更高层级 index
   * 避免跨页拖动太快控件被页面遮挡
   */
  &.is-active {
    z-index: 2;
  }

  &__wrap,
  &__img,
  &__html {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
  }

  &__wrap {
    background-color: #fff;
  }

  &__img,
  &__html {
    &[lazy='loading'] {
      @include imgLoadingAnimation(linear-gradient(90deg, #fff 40%, #f9f9f9 50%, #fff 60%));
    }
  }

  &__img {
    user-select: none;
  }
}
</style>
